﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ArgusLib.Threading.Collections
{
	public interface ISynchronizedEnumerator<T> : IEnumerator<T>
	{
		object SyncRoot { get; }
	}

	public abstract class SynchronizedEnumeratorBase<T> : ISynchronizedEnumerator<T>
	{
		public object SyncRoot { get; private set; }

		public SynchronizedEnumeratorBase()
			: this(new object()) { }

		public SynchronizedEnumeratorBase(object syncRoot)
		{
			if (syncRoot == null)
				throw new ArgumentNullException("syncRoot");
			this.SyncRoot = syncRoot;
			this.Reset();
		}

		private void AcquireLock()
		{
			try
			{
				Monitor.Exit(this.SyncRoot);
			}
			catch (SynchronizationLockException) { }
			Monitor.Enter(this.SyncRoot);
		}

		private void ReleaseLock()
		{
			try
			{
				Monitor.Exit(this.SyncRoot);
			}
			catch (SynchronizationLockException) { }
		}

		public abstract T Current { get; }
		object IEnumerator.Current { get { return this.Current; } }

		public void Reset()
		{
			this.AcquireLock();
			this.ResetCore();
		}

		protected abstract void ResetCore();

		public bool MoveNext()
		{
			bool RetVal = this.MoveNextCore();
			if (RetVal == false)
				Monitor.Exit(this.SyncRoot);
			return RetVal;
		}

		protected abstract bool MoveNextCore();

		void IDisposable.Dispose()
		{
			this.ReleaseLock();
		}
	}
}
